#pragma once
#include <iostream>
#include <vector>
#include<pthread.h>
#include <semaphore.h>

namespace Mango
{
    const int cap_default = 10;
    template<class T>
    class RingQueue
    {
        public:
        RingQueue(int cap = cap_default)
            :_cap(cap),c_step(0),p_step(0)
        {
            _ringqueue.resize(cap);
            //初始化信号量,第三个参数:信号量的初始值
            sem_init(&blank_sem, 0, cap);//最初有cap个空格子资源
            sem_init(&data_sem, 0, 0);//最初没有数据,数据资源为0

            //初始化互斥锁
            pthread_mutex_init(&c_mtx_, nullptr);
            pthread_mutex_init(&p_mtx_, nullptr);
        }
        ~RingQueue()
        {
            sem_destroy(&blank_sem);
            sem_destroy(&data_sem);
            
            //释放互斥锁
            pthread_mutex_destroy(&c_mtx_);
            pthread_mutex_destroy(&p_mtx_);
        }

        //插入数据->生产者使用
        void Push(const T& in)
        {
            //step1:申请信号量
            sem_wait(&blank_sem);//生产者要申请空位置的资源,P操作(空位置)
            //访问临界资源前先加锁:
            pthread_mutex_lock(&p_mtx_);
            //step2:在当前p_step位置生产(放数据)
            _ringqueue[p_step] = in;
            //step3:多了一个数据->数据资源增加(V操作(数据资源))
            sem_post(&data_sem);
            //step4:处理p_step的位置,防止越界
            p_step++;
            p_step %=_cap;
            pthread_mutex_unlock(&p_mtx_);//解锁
        }

        //弹出数据->消费者使用
        void Pop(T* out)//输出型参数
        {
            //step1:申请信号量
             sem_wait(&data_sem);  //消费者要申请数据资源,P操作(数据资源)
            //访问临界资源前先加锁:
            pthread_mutex_lock(&c_mtx_);
            //step2:取出在c_step位置的数据(拿数据)
            *out = _ringqueue[c_step];
            //step3:少了一个数据->空间资源增加(V操作(空间资源))
            sem_post(&blank_sem);
            //step4:处理c_step的位置,防止越界
            c_step++;
            c_step %= _cap;
            pthread_mutex_unlock(&c_mtx_);
        }
        private:
            std::vector<T> _ringqueue;//数组模拟实现环形队列
            int _cap;//记录容量
            sem_t blank_sem;//描述空间资源->生产者关心空位置资源
            sem_t data_sem;//描述数据资源->消费者关心数据资源
            int c_step;//消费者当前所在的位置
            int p_step;//生产者当前所在的位置

            //新增:两把锁,保护临界资源
            pthread_mutex_t c_mtx_;
            pthread_mutex_t p_mtx_;
    };
}
